#include "storage.h"

void *pthread_client_request(void *arg);//处理消息队列里请求的线程.
void *pthread_transfer(void *arg);//接收M0数据线程.
void *pthread_analysis(void *arg);//M0数据分析线程.

#define A53_BEEP_ON 0
#define A53_BEEP_OFF 1
#define A53_LED_ON 2
#define A53_LED_OFF 3 

pthread_cond_t cond[6]; //条件变量
pthread_t tid[6] = {};	//线程ID
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;//互斥锁
pthread_mutex_t mutex1;
pthread_mutex_t mutex2; 
struct sendEnv msg;
struct sendEnv *addr = NULL;//共享内存
int msgid; 					//消息队列
int cmd = 67;					//网页和QT的发的命令

void serial_init(int fd) //初始化串口
{
	printf("%s:%d\n",__func__,__LINE__);
	struct termios options;
	tcgetattr(fd, &options);// 获取终端设置的参数
	options.c_cflag |= ( CLOCAL | CREAD );//控制模式
	options.c_cflag &= ~CSIZE;
	options.c_cflag &= ~CRTSCTS;
	options.c_cflag |= CS8;
	options.c_cflag &= ~CSTOPB;
	options.c_iflag |= IGNPAR;			//输入模式
	options.c_iflag &= ~(ICRNL | IXON);
	options.c_oflag = 0;				//输出模式
	options.c_lflag = 0;				//本地模式

	cfsetispeed(&options, B115200); //设置输入的波特率
	cfsetospeed(&options, B115200);	//设置输出的波特率
	tcsetattr(fd,TCSANOW,&options);	//设置终端参数 第二个参数  不等数据传输完立即改变属性
}

void initialization()//打开设备文件
{
	printf("%s:%d\n",__func__,__LINE__);
#if 0	
	DEVICE_LED = open("/dev/myled0",O_RDWR);
	if(DEVICE_LED==-1)
		printf("myled0 open failed\n");
	DEVICE_BEEP = open("/dev/mybeep0",O_RDWR);
	if(DEVICE_BEEP==-1)
		printf("mybeep0 open failed\n");
#endif 
	DEVICE_M0 = open("/dev/ttyUSB0",O_RDWR);
	if(DEVICE_M0==-1){
		printf("ttyUSB0 open failed\n");
	}else{
		serial_init(DEVICE_M0);//初始化MO
		write(DEVICE_M0,&cmd,sizeof(int)); //测试先写入  蜂鸣器
	}
}

int main(int argc, const char *argv[])
{

#if 0
	//创建根节点
	LinkNode *base;
	create_node(&base);
#endif 
	int i=0;

	//创建key值
	key_t key;
	key = ftok("/", 'a');
	if(key == -1) {
		perror("ftok");
		return -1;
	}
	//申请物理地址
	int shmid = shmget(key, sizeof(struct sendEnv), IPC_CREAT|0777);
	if(shmid == -1) {
		perror("shmget");
		return shmid;
	}
	//申请虚拟地址并且映射
	addr = (struct sendEnv *)shmat(shmid, NULL, 0);
	if(addr == NULL ) {
		perror("shmat");
		return -1;
	}

	//获取消息队列
	msgid = msgget(key, IPC_CREAT|0777);
	if(msgid == -1) {
		perror("msgget");
		return -1;
	}

	//创建一个数据库  
	if(sqlite3_open(STORAGE_SQL,&db) != SQLITE_OK)
	{
		printf("%s.\n",sqlite3_errmsg(db));
	}else{
		printf("storage sqlite create success\n");
	}

	char * errmsg = NULL;
	char sql_buf[1024] = {}; 
	//创建三个仓库storage[1].[2].[3]
	for(i=1;i<=3;i++){
		memset(sql_buf,0, 1024);
		sprintf(sql_buf,"create table if not exists storage%d"
				"(head text,"
				"type char,"
				"snum char,"
				"temp text,"
				"hum text,"
				"x char,y char,z char,"
				"ill int,"
				"bet int,"
				"adc int);",i);
		if(sqlite3_exec(db,sql_buf,NULL,NULL,&errmsg)!= SQLITE_OK){
			printf("%s\n",errmsg);
			printf("%s:%d\n",__func__,__LINE__);
			printf("%s:%d\n",__func__,__LINE__);
		}else
		{
			printf("create storage[%d] success.\n",i);
		}
	}
	//fflush(stdout);

	initialization(); //打开设备文件
	


	pthread_mutex_init(&mutex,NULL); //初始化锁
	pthread_mutex_init(&mutex1,NULL); //初始化锁
	pthread_mutex_init(&mutex2,NULL); //初始化锁
	for(i=0;i<6;i++){
		if(pthread_cond_init(&cond[i],NULL)!=0){
			printf("init cind[%d] error\n",i);
			exit(1);
		}

	}
	/******接收处理M0发来的数据 将处理好的数据发送的线程*****/
	if(pthread_create(&tid[0],NULL,pthread_transfer,NULL)!=0){
		perror("pthread_create tid0");
	}
	pthread_detach(tid[0]);

	/**************M0数据分析线程***************/
	if(pthread_create(&tid[1],NULL,pthread_analysis,NULL)!=0){
		perror("pthread_create tid1");
	}
	pthread_detach(tid[1]);

	/************处理消息队列请求的线程*********/
	if(pthread_create(&tid[2],NULL,pthread_client_request,NULL)!=0){
		perror("pthread_create tid2");
	}
	pthread_detach(tid[2]);

#if 0
	/***********更新共享内存里的实时数据***********/
	if(pthread_create(&tid[2],NULL,pthread_refresh,NULL)!=0){
		perror("pthread_create tid2");
	}
	pthread_detach(tid[2]);
#endif

#if 0
	/**************A53蜂鸣器控制线程***********/
	if(pthread_create(&tid[3],NULL,pthread_buzzer,NULL)!=0){
		perror("pthread_create tid3");
	}
	pthread_detach(tid[3]);

	/***************A53LED控制线程*************/
	if(pthread_create(&tid[4],NULL,pthread_led,NULL)!=0){
		perror("pthread_create tid4");
	}
	pthread_detach(tid[4]);
#endif


	while(1);//不让主进程退出


	pthread_mutex_destroy(&mutex);//销毁锁
	pthread_mutex_destroy(&mutex1);//销毁锁
	pthread_mutex_destroy(&mutex2);//销毁锁
	for(i=0;i<6;i++){// 销毁条件变量
		if(pthread_cond_destroy(&cond[i])!=0){
			printf("destroy cond[%d] error\n",i);
			exit(1);
		}
	}

	// 取消映射
	shmdt(addr);
	//删除共享内存
	shmctl(shmid,IPC_RMID,NULL);
	return 0;
}

//接收M0数据线程
void *pthread_transfer(void *arg)
{
	printf("%s:%d\n",__func__,__LINE__);
	char sql_buf[128] = {};
	int i,ret;
	char * errmsg = NULL;
	while(1){
		pthread_mutex_lock(&mutex); 	//上锁  读M0数据的时候不能被打断
		//pthread_cond_wait(&cond[0], &mutex);
		ret = read(DEVICE_M0,&msg,sizeof(struct sendEnv));	
		if(ret < 0){
			perror("read error");
			exit(1);
		}
		sprintf(sql_buf,"insert into storage1 values('%c%c%c','%c',%d,\
			'%d.%d','%d.%d',%d,%d,%d,%d,%d,%d)",msg.head[0],msg.head[1],\
			msg.head[2],msg.type,msg.snum,msg.temp[0],msg.temp[1],\
			msg.hum[0],msg.hum[1],msg.x,msg.y,msg.z,msg.ill,msg.bet,\
			msg.adc);
		if(sqlite3_exec(db,sql_buf,NULL,NULL,&errmsg) != SQLITE_OK){
			fprintf(stderr,"%s\n",errmsg);
			exit(1);
		}else{
			puts("---数据入库成功---");
		}
		bzero(sql_buf,sizeof(sql_buf));

		printf("接收的大小 %d\n",ret);
		printf("head = %c%c%c\n",msg.head[0],msg.head[1],msg.head[2]);
		printf("type = %c\n",msg.type);
		printf("snum = %d\n",msg.snum);
		printf("temp = %d.%d\n",msg.temp[0],msg.temp[1]);
		printf("hum = %d.%d\n",msg.hum[0],msg.hum[1]);
		printf("x = %d\n",msg.x);
		printf("y = %d\n",msg.y);
		printf("z = %d\n",msg.z);
		printf("ill = %d\n",msg.ill);
		printf("bet = %d\n",msg.bet);
		printf("adc = %d\n",msg.adc);
		pthread_mutex_unlock(&mutex); //解锁执行其他线程
		pthread_cond_signal(&cond[1]); //唤醒数据处理线程
	
		sleep(3);
	}
}

/*******M0数据分析处理线程***********/
void *pthread_analysis(void *arg)
{
	printf("%s:%d\n",__func__,__LINE__);
	while(1){
		pthread_mutex_lock(&mutex1);
		pthread_cond_wait(&cond[1], &mutex1);
		/*************操作************/

		/*******将数据写到共享内存并且更新******/ 
		memcpy(addr,&msg,sizeof(struct sendEnv));
		/*******将数据发送给QT 使用消息队列*******/
		MSG_QUEUE msq;
		msq.type = 1;			//往QT发送的消息类型
		msq.cmdtype = 1;
		memcpy(msq.text, &msg, sizeof(struct sendEnv));		
		int ret = msgsnd(msgid,&msq,sizeof(MSG_QUEUE)-sizeof(long),0);
		if(ret == -1) {
			perror("msgsend");
			exit(1);
		}
		pthread_mutex_unlock(&mutex1);
		pthread_cond_signal(&cond[2]);
	}
}

/*********处理消息队列请求的线程**********/
void *pthread_client_request(void *arg)
{
	int ret,rcv_cmdtype;
	MSG_QUEUE rcv_msq;
	printf("%s:%d\n",__func__,__LINE__);
	while(1){
		pthread_mutex_lock(&mutex2);
		pthread_cond_wait(&cond[2], &mutex2);
		//操作
		/********从消息队列接收消息类型 0:QT 2:WEB *******/
		//1先接收网页WEB
		ret = msgrcv(msgid, &rcv_msq,sizeof(MSG_QUEUE)-sizeof(long),2,IPC_NOWAIT);
		if(ret < 0){
			perror("msgrcv");
		}else if(ret > 0){
			//判断接收的命令
			rcv_cmdtype = rcv_msq.cmdtype;//控制 A53 OR M0  
			int cmd = (int)rcv_msq.text[0];
			if(rcv_cmdtype == 0){
				write(DEVICE_M0,&cmd,sizeof(int));//向M0写数据
					/**********M0 风扇状态：关 0.1.2.3 -> 64,65,66,67***************/
					/**********M0 LED 关 开-> 96,97***************/
					/**********M0 蜂鸣器状态 关开->80,81***************/
			}else if(rcv_cmdtype == 1){
					/*******BEEP:开关01  LED:开关23  ******************/
					switch(cmd){
					case A53_BEEP_ON:
						write(DEVICE_BEEP,&cmd,sizeof(int));//A53 BEEP 开命令
						break;
					case A53_BEEP_OFF:
						write(DEVICE_BEEP,&cmd,sizeof(int));//A53 BEEP关命令
						break;
					case A53_LED_ON:
						write(DEVICE_LED,&cmd,sizeof(int));//A53 LED开命令
						break; 
					case A53_LED_OFF:
						write(DEVICE_LED,&cmd,sizeof(int));//A53 LED关命令
						break;
					default:
						break;
					}
			}
		}
		/****************A53硬件驱动未完成**************************/
#if 0
		//2接收QT的命令
		ret = msgrcv(msgid, &rcv_msq,sizeof(rcv_msq)-sizeof(long),0,IPC_NOWAIT);
		if(ret < 0){
			perror("msgrcv");
		}else if(ret > 0){
			//判断接收的命令
			rcv_cmdtype = rcv_msq.cmdtype;//控制 A53 OR M0  
			int cmd = (int)rcv_msq.text[0];
			if(rcv_cmdtype == 0){
				write(DEVICE_M0,&cmd,sizeof(int));//向M0写数据
					/**********M0 风扇状态：关 0.1.2.3 -> 64,65,66,67***************/
					/**********M0 LED 关 开-> 96,97***************/
					/**********M0 蜂鸣器状态 关开->80,81***************/
			}else if(rcv_cmdtype == 1){
					/*******BEEP:开关01  LED:开关23  ******************/
					switch(cmd){
					case A53_BEEP_ON:
						write(DEVICE_BEEP,&cmd,sizeof(int));//A53 BEEP 开 命令
						break;
					case A53_BEEP_OFF:
						write(DEVICE_BEEP,&cmd,sizeof(int));//A53 BEEP 关 命令
						break;
					case A53_LED_ON:
						write(DEVICE_LED,&cmd,sizeof(int));//A53 LED 开 命令
						break; 
					case A53_LED_OFF:
						write(DEVICE_LED,&cmd,sizeof(int));//A53 LED 关 命令
						break;
					default:
						break;
					}
			}
		}
				
#endif	
		pthread_mutex_unlock(&mutex2);
		pthread_cond_signal(&cond[3]);
	}
}



